#include <config.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/asm.h>

#include "ns16550.h"
#include "i2c.h"

#define msize		s2

/*
 * Register usage:
 *
 *	s0	link versus load offset, used to relocate absolute adresses.
 *	s1	ddr param
 *	s2	memory size.
 * s3 dimm param
 */

	.set   mips64
FEXPORT(lowlevel_init)
	move   k1, ra

	//SPI init
	li   v0, 0xbfff0220
	li   v1, 0xff
	sb   v1, 0x5(v0) //set all spi cs to 1, default input
	li   v1, 0x47
	sb   v1, 0x4(v0) //spi speedup
	li   v1, 0x01
	sb   v1, 0x6(v0)

	lui   t0, 0xba00
	lui   t1, 0x1fe0
	sw    t1, 0x1010(t0) /* config bar for APB */
	lw    t2, 0x1004(t0)
	ori   t2, t2, 0x2
	sw    t2, 0x1004(t0)

#if 1
	//fix the hardware poweroff error.
	mfc0  t0, $15, 1      #EBASE
	andi  t0, t0, 0x3ff
	bnez  t0, 2f
	nop

	li    t0, 0xbfe0700c
	lw    t1, 0x0(t0) //APCI PM1_STS
	and   t2, t1,(1 << 11)
	beqz  t2, 2f
	nop

	li    t0, 0xbfe0700c
	lw    t1, 0x0(t0)
	sw    t1, 0x0(t0)
	li    t2, 0x3c00
	li    t0, 0xbfe07014
	sw    t2, 0x0(t0) //ACPI PM1_CNT
2:
#endif

cp0_main:
	mfc0    t0, $15, 1      #EBASE
	andi    t0, t0, 0x3ff
	bnez    t0, wait_for_smp
	nop

#ifdef BEEP_DEBUG_GPIO
	bal	beep_on
	nop

	li	a0, 0x2000
1:
	addiu	a0, -1
	nop
	bnez	a0, 1b
	nop
	bal	beep_off
	nop
#endif

	//xwr pcie signal test
	li t0, 0xbfe10000

	li	t1, 0xc2492331
	sw	t1, 0x580(t0)
	sw	t1, 0x5a0(t0)

	li	t1, 0xff3ff0a8
	sw	t1, 0x584(t0)
	sw	t1, 0x5a4(t0)

	li	t1, 0x27fff
	sw	t1, 0x588(t0)
	sw	t1, 0x5a8(t0)

	/* mtf add for cfg pcie */
	li  t0, 0xbfe10590
	dli t1, 0x14fff1002
	sd  t1, 0x0(t0)
	sd  t1, 0x20(t0)

	dli t1, 0x14fff1102
	sd  t1, 0x0(t0)
	sd  t1, 0x20(t0)

	dli t1, 0x14fff1202
	sd  t1, 0x0(t0)
	sd  t1, 0x20(t0)

	dli t1, 0x14fff1302
	sd  t1, 0x0(t0)
	sd  t1, 0x20(t0)

	li  t0, 0xbfe10430
	lw  t1, 0x0(t0)
	or  t1, t1, 0x30000	//pcie enable
	sw  t1, 0x0(t0)

	//pcie1 port0
	dli t0, 0x900000fe0800680c
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe0700681c
	lw  t2, 0x0(t0)
	li  t1, (0x1 << 26)
	or  t2, t1
	sw  t2, 0x0(t0)

	dli t0, 0x900000fe00006800
	li  t1, 0x10000000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x10000000
	or  t0, t0, t1

	li  t1, (0x7<<18)|(0x7<<2)
	not t1, t1
	lw  t2, 0x54(t0)
	and t2, t2, t1
	sw  t2, 0x54(t0)

	lw  t2, 0x58(t0)
	and t2, t2, t1
	sw  t2, 0x58(t0)

	dli t1, 0xff204f
	sw  t1, 0x0(t0)

	//pcie1 port1
	dli t0, 0x900000fe0800700c
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe0700701c
	lw  t2, 0x0(t0)
	li  t1, (0x1 << 26)
	or  t2, t1
	sw  t2, 0x0(t0)

	dli t0, 0x900000fe00007000
	li  t1, 0x10100000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x10100000
	or  t0, t0, t1

	li  t1, (0x7<<18)|(0x7<<2)
	not t1, t1
	lw  t2, 0x54(t0)
	and t2, t2, t1
	sw  t2, 0x54(t0)

	lw  t2, 0x58(t0)
	and t2, t2, t1
	sw  t2, 0x58(t0)

	dli t1, 0xff204c
	sw  t1, 0x0(t0)

	//pcie0 port0
	dli t0, 0x900000fe0800480c	//other pcie controller
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe0700481c
	lw  t2, 0x0(t0)
	li  t1, (0x1 << 26)
	or  t2, t1
	sw  t2, 0x0(t0)

	dli t0, 0x900000fe00004800
	li  t1, 0x11000000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x11000000
	or  t0, t0, t1

	li  t1, (0x7<<18)|(0x7<<2)
	not t1, t1
	lw  t2, 0x54(t0)
	and t2, t2, t1
	sw  t2, 0x54(t0)

	lw  t2, 0x58(t0)
	and t2, t2, t1
	sw  t2, 0x58(t0)

	dli t1, 0xff204c
	sw  t1, 0x0(t0)

	//pcie0 port1
	dli t0, 0x900000fe0800500c	//other pcie controller
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe0700501c
	lw  t2, 0x0(t0)
	li  t1, (0x1 << 26)
	or  t2, t1
	sw  t2, 0x0(t0)

	dli t0, 0x900000fe00005000
	li  t1, 0x11100000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x11100000
	or  t0, t0, t1

	li  t1, (0x7<<18)|(0x7<<2)
	not t1, t1
	lw  t2, 0x54(t0)
	and t2, t2, t1
	sw  t2, 0x54(t0)

	lw  t2, 0x58(t0)
	and t2, t2, t1
	sw  t2, 0x58(t0)

	dli t1, 0xff204c
	sw  t1, 0x0(t0)

	//pcie0 port2
	dli t0, 0x900000fe0800580c	//other pcie controller
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe00005800
	li  t1, 0x11200000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x11200000
	or  t0, t0, t1

	dli t1, 0xff204c
	sw  t1, 0x0(t0)

	//pcie0 port3
	dli t0, 0x900000fe0800600c	//other pcie controller
	li  t1, 0xfff9ffff
	lw  t2, 0x0(t0)
	and t1, t1, t2
	or  t1, 0x20000
	sw  t1, 0x0(t0)

	dli t0, 0x900000fe00006000
	li  t1, 0x11300000
	sw  t1, 0x10(t0)

	dli t0, 0x9000000000000000
	li  t1, 0x11300000
	or  t0, t0, t1

	dli t1, 0xff204c
	sw  t1, 0x0(t0)

#ifdef CONFIG_BOARD_LS2K_PC_EVB
	bal watchdog_close
	nop
#endif

	//初始化调试串口，2k没配置前的启动频率默认100MHz
	li  a0, (OSC_CLK/16)/CONFIG_BAUDRATE
	bal initserial
	nop

	PRINTSTR("\r\nserial init ok\r\n")
	nop

	//配置2k的cpu频率、内存频率、apb频率等
#include "ls2k_clk_config.S"

#if 0 /* Config SATA : use internel clock */
	li   t1, 0xbfe10450
	li   t0, 0x30c31cf9
	sw   t0, 0x4(t1)
	li   t0, 0xf300040f
	sw   t0, 0x0(t1)

	ld   a0, 0x0(t1)
	li   a1, 0x2
	not  a1, a1
	and  a0, a0, a1
	sd   a0, 0x0(t1)
	sync

	ld   a0, 0x0(t1)
	li   a1, 0x4
	or   a0, a1
	sd   a0, 0x0(t1)
	sync

	ld   a0, 0x0(t1)
	li   a1, 0x8
	or   a0, a1
	sd   a0, 0x0(t1)
	sync
#endif

#if 1
	// Fix the Gmac0  multi-func to enable Gmac1
	li   t0, 0xbfe13800
	dli  a0, 0xffffff0000ffffff
	sd   a0, 0x08(t0)

	li   t0, 0xba001800
	li   a0, 0x0080ff08
	sw   a0, 0x0c(t0)
#endif

#if 1
	// Set the invalid BAR to read only
	li   t0, 0xbfe13800
	dli  a0, 0xffffff0000fffff0
	sd   a0, 0x00(t0)
	sd   a0, 0x08(t0)
	sd   a0, 0x10(t0)
	sd   a0, 0x18(t0)
	sd   a0, 0x20(t0)
	sd   a0, 0x28(t0)
	sd   a0, 0x30(t0)
	sd   a0, 0x38(t0)
	sd   a0, 0x40(t0)
	sd   a0, 0x48(t0)
	sd   a0, 0x50(t0)
#endif

	mfc0 a0, CP0_CONFIG		/* enable kseg0 cachability */
	ori  a0, a0, 0x3        // ENABLE
	mtc0 a0, CP0_CONFIG

	li  t0, 0xbfe10430
	lw  a2, 0x0(t0)
	//pcie0 and pcie1
	lui t1, 0x3
	//enable dvo0 and dvo1 pin output
	ori t1, t1, 0x12
	or  a2, a2, t1
	sw  a2, 0x0(t0)

	li  t0, 0xbfe10420
	lw  t2, 0x0(t0)
	lui t1, 0x10
	//enable pwm0, pwm1, i2c0, i2c1, nand, sata, i2s, gmac1
	//no hda, no ac97
	ori t1, t1, 0x3f48
	or  t2, t2, t1
	sw  t2, 0x0(t0)

//##########################################
//DDR config start
//cxk
#include "mm/lsmc_ddr_param_define.h"
#include "mm/ddr_config_define.h"
//#define DDR_DLL_BYPASS
#define DISABLE_DIMM_ECC
#define PRINT_MSG
#ifdef  ARB_LEVEL
#define AUTO_ARB_LEVEL
#endif
#ifdef  AUTO_ARB_LEVEL
//#define CHECK_ARB_LEVEL_FREQ
#ifdef  AUTO_DDR_CONFIG
#define CHECK_ARB_LEVEL_DIMM
#endif
//#define DEBUG_AUTO_ARB_LEVEL
#endif
//#define DEBUG_DDR
//#define DEBUG_DDR_PARAM
//#define PRINT_DDR_LEVELING

	TTYDBG("\r\nInit Memory begin, wait a while......\r\n")
####################################
	move   msize, $0
	move   s3, $0
//!!!!important--s1 must be correctly set
#ifdef  AUTO_DDR_CONFIG
	dli   s1, 0xff100004  //set use MC1 or MC0 or MC1/0 and give All device id
#elif defined(DDR_S1)
	dli   s1, DDR_S1
#else
	//dli     s1, 0xc2e30400c2e30404
	//dli     s1, 0xc1a10404
	//dli	s1, 0xc0a10400c0a10400
	//dli	s1, 0xc0a18404
	//dli	s1, 0xf0a31004
	//dli	s1, 0xc1a10404
	dli   s1, ( MC_SDRAM_TYPE_DDR3    /* sdram type: DDR3/DDR2 */ \
		| MC_DIMM_ECC_NO        /* dimm ECC: YES/NO */ \
		| MC_DIMM_BUF_REG_NO    /* dimm buffer register: YES/NO, for RDIMM use YES, all else use NO*/ \
		| MC_DIMM_WIDTH_64      /* memory data width: 64/32 */ \
		| MC_SDRAM_ROW_16       /* sdram row address number: 15~11 */ \
		| MC_SDRAM_COL_10       /* sdram column address number: 12~9 */ \
		| MC_SDRAM_BANK_8       /* sdram bank number: 8/4 */ \
		| MC_ADDR_MIRROR_NO    /* for standard DDR3 UDIMM, use YES, else use NO */ \
		| MC_SDRAM_WIDTH_X16     /* SDRAM device data width: 8/16 */ \
		| MC_USE_CS_0         /* the CS pins the sdram connected on(split by '_', from small to big) */ \
		| MC_MEMSIZE_(8)        /* MC memory size, unit: 512MB */ \
		| USE_MC_0)
#endif

#include "mm/loongson3_ddr2_config.S"

	/*judge the node0 whether have memory*/
	and     a0, msize, 0xff

	//close default internal mapping in ddr controller
	li      t0, 0xbfe10424
	lb      a0, 0x1(t0)
	and     a0, a0, 0xfd
	ori     a0, a0, 0x01
	sb      a0, 0x1(t0)
	sync

	TTYDBG("\r\nInit Memory success\r\n")
#if 0
	/* test memory */
	li      t0, 0xa0000000
	dli     a0, 0x5555555555555555
	sd      a0, 0x0(t0)
	dli     a0, 0xaaaaaaaaaaaaaaaa
	sd      a0, 0x8(t0)
	dli     a0, 0x3333333333333333
	sd      a0, 0x10(t0)
	dli     a0, 0xcccccccccccccccc
	sd      a0, 0x18(t0)
	dli     a0, 0x7777777777777777
	sd      a0, 0x20(t0)
	dli     a0, 0x8888888888888888
	sd      a0, 0x28(t0)
	dli     a0, 0x1111111111111111
	sd      a0, 0x30(t0)
	dli     a0, 0xeeeeeeeeeeeeeeee
	sd      a0, 0x38(t0)


	PRINTSTR("The uncache data is:\r\n")
	dli     t1, 8
	dli     t2, 0x9000000000000000
1:
	ld      t3, 0x0(t2)
	move    a0, t2
	and     a0, a0, 0xfff
	bal     hexserial
	nop
//	PRINTSTR(":  ")
	dsrl    a0, t3, 32
	bal     hexserial
	nop
	move    a0, t3
	bal     hexserial
	nop
	PRINTSTR("\r\n")

	daddiu  t1, t1, -1
	daddiu  t2, t2, 8
	bnez    t1, 1b
	nop

	PRINTSTR("The cached  data is:\r\n")
	dli     t1, 8
	dli     t2, 0x9800000000000000
1:
	ld      t3, 0x0(t2)
	move    a0, t2
	and     a0, a0, 0xfff
	bal     hexserial
	nop
//	PRINTSTR(":  ")
	dsrl    a0, t3, 32
	bal     hexserial
	nop
	move    a0, t3
	bal     hexserial
	nop
	PRINTSTR("\r\n")

	daddiu  t1, t1, -1
	daddiu  t2, t2, 8
	bnez    t1, 1b
	nop
#endif
##########################################
#ifdef  DEBUG_DDR
	PRINTSTR("\r\nDo test?(0xf: skip): ")
	bal     inputaddress
	nop
	and     v0, v0, 0xf
	dli     a1, 0x1
	bgt     v0, a1, 2f
	nop
	dli     s1, 0x0010000080000000
	PRINTSTR("\r\ndefault s1 = 0x");
	dsrl    a0, s1, 32
	bal     hexserial
	nop
	PRINTSTR("__")
	move    a0, s1
	bal     hexserial
	nop
	PRINTSTR("\r\nChange test param s1(0: skip)?: ")
	bal     inputaddress
	nop
	beqz    v0, 1f
	nop
	move    s1, v0
1:
	dli     t1, 0x0010
	bal     test_mem
	nop
	move    t1, v0
	PRINTSTR("\r\n")
	dsrl    a0, t1, 32
	bal     hexserial
	nop
	move    a0, t1
	bal     hexserial
	nop
	beqz    t1, 2f
	nop
	PRINTSTR("  Error found!!\r\n")
2:
#endif

#ifdef  AUTO_ARB_LEVEL
//#include "mm/store_auto_arb_level_info.S"
#endif

bootnow:
	jr k1
	nop

	.global wait_for_smp;
	.global wait_for_smp_call;
wait_for_smp:
	mfc0  t1, CP0_CONFIG
	ori   t1, t1, 0x3
	mtc0  t1, CP0_CONFIG
	la    t1, 1f
	addu  t1, s0
	li    v0, 0x9fffffff
	and   t1, v0
	jr    t1
	nop
1:
	li    t0, 0xbfe11120
	sd    zero, 0(t0)
	sd    t1, 8(t0)

wait_for_smp_call:
1:
	ld    t1, 0(t0)
	beqz  t1, 1b
	ld    sp, 8(t0)
	sd    zero, 0(t0)
	ld    gp, 16(t0)

	jr    t1
	nop


LEAF(initserial)
.set noat
	move AT, ra

	li   v0, UART_BASE_ADDR
	li   v1, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4
	sb   v1, NSREG(NS16550_FIFO)(v0)
	li   v1, CFCR_DLAB                  #DLAB
	sb   v1, NSREG(NS16550_CFCR)(v0)
	sb   a0, NSREG(NS16550_DATA)(v0)
	srl  a0, 8
	sb   a0, NSREG(NS16550_IER)(v0)     #set BRDH
	li   v1, CFCR_8BITS                 #8bit
	sb   v1, NSREG(NS16550_CFCR)(v0)
	li   v1, MCR_DTR|MCR_RTS
	sb   v1, NSREG(NS16550_MCR)(v0)
	li   v1, 0x0
	sb   v1, NSREG(NS16550_IER)(v0)

	jr    ra
	nop
.set at
END(initserial)

LEAF(printk)
	.set noreorder
	move  a2, ra
	move  a1, a0
	lbu   a0, 0(a1)
1:
	beqz  a0, 2f
	nop
	bal   tgt_putchar
	nop
	addiu a1, 1
	lbu   a0, 0(a1)
	b     1b
	nop
2:
	jr    a2
	nop
	.set reorder
END(printk)

tgt_putchar:
	la   v0, CONFIG_SYS_NS16550_COM1
1:
	lbu  v1, NSREG(NS16550_LSR)(v0)
	and  v1, LSR_TXRDY
	beqz v1, 1b
	nop

	sb   a0, NSREG(NS16550_DATA)(v0)
	jr   ra
	nop

	.rdata
hexchar:
	.ascii	"0123456789abcdef"
	.text

LEAF(hexserial)
	move  a2, ra
	move  a1, a0
	li    a3, 8
1:
	rol   a0, a1, 4
	move  a1, a0
	and   a0, 0xf
	la    t0, hexchar
	addu  t0, s0
	addu  t0, a0
	lbu   a0, 0(t0)
	bal   tgt_putchar

	addu  a3, -1
	bnez  a3, 1b
	nop

	jr    a2
	nop
END(hexserial)

LEAF(hexserial64)
	move	t7, ra
	jr	t7
   nop
END(hexserial64)

#ifdef BEEP_DEBUG_GPIO
LEAF(beep_on)
	li  t1, 0xbfe10500 + BEEP_DEBUG_GPIO*4/32
	li  v1, (1<<(BEEP_DEBUG_GPIO&31))
	lw  t0, 0(t1)
	or  t0, v1
	xor t0, v1
	sw  t0, 0(t1)
	lw  t0, 0x10(t1)
	or  t0, v1
	sw  t0, 0x10(t1)

	jr  ra
	nop
END(beep_on)

LEAF(beep_off)
	li  t1, 0xbfe10500 + BEEP_DEBUG_GPIO*4/32
	li  v1, (1<<(BEEP_DEBUG_GPIO&31))
	lw  t0, 0(t1)
	or  t0, v1
	xor t0, v1
	sw  t0, 0(t1)
	lw  t0, 0x10(t1)
	or  t0, v1
	xor t0, v1
	sw  t0, 0x10(t1)

	jr  ra
	nop
END(beep_off)
#endif

#ifdef CONFIG_BOARD_LS2K_PC_EVB
LEAF(watchdog_close)
	//disable watch DOG.
	//gpio 3 output zero
	li  t1, 0xbfe10500

	li  t2, (1 << 3)
	not t2, t2
	lw  t3, 0x0(t1)
	and t2, t3
	sw  t2, 0x0(t1)

	li  t2, (1 << 3)
	lw  t3, 0x10(t1)
	not t2, t2
	and t2, t3
	sw  t2, 0x10(t1)
	nop

	jr  ra
	nop
END(watchdog_close)
#endif

#include "i2c.S"

#ifdef  AUTO_DDR_CONFIG
#include "mm/detect_node_dimm_all.S"
#endif

#include "mm/ls3A8_ddr_config.S"
#ifdef DDR3_DIMM
#include "mm/loongson3C_ddr3_leveling.S"
#endif
#ifdef ARB_LEVEL
//#include "mm/ARB_level_new.S"
#endif
#ifdef  DEBUG_DDR
#include "mm/Test_Mem.S"
#endif
    .align  5
#ifdef CONFIG_DDR_32BIT
#include "loongson_mc2_param-ddr32bit.S"
//#elif defined(CONFIG_DDR_16BIT)
//#include "loongson_mc2_param-ddr16bit.S"
#else
#include "loongson_mc2_param.S"
#endif

#ifdef  ARB_LEVEL
	.text
	.global c0_mc0_level_info
	.global c0_mc1_level_info
#ifdef  MULTI_CHIP
	.global c1_mc0_level_info
	.global c1_mc1_level_info
#endif

#include "mm/loongson3A3_ddr_param.lvled.S"
#ifdef  MULTI_CHIP
#include "mm/loongson3A3_ddr_param_c1.lvled.S"
#endif

#endif
